/******************************************************************************
 Copyright (c) 2022-2025 Qualcomm Technologies International, Ltd.
 All Rights Reserved.
 Qualcomm Technologies International, Ltd. Confidential and Proprietary.

 REVISION:      $Revision: #14 $
******************************************************************************/

#include "csr_synergy.h"

#ifndef EXCLUDE_GATT_XPAN_SERVER_MODULE

#include "gatt_xpan_server_access.h"
#include <stringl/stringl.h>

#define CONNECT_SSID_TYPE_OFFSET            (2)
#define DISCONNECT_SSID_TYPE_OFFSET         (2)
#define CONNECTED_SSID_TYPE_OFFSET          (2)
#define AVAILABLE_SSID_TYPE_OFFSET          (2)
#define RELATED_SSIDS_TYPE_OFFSET           (2)
#define MDNS_SRV_UUID_TYPE_OFFSET           (2)
#define REMOVE_SSID_TYPE_OFFSET             (2)
#define L2CAP_TCP_PORT_TYPE_OFFSET          (2)
#define UDP_PORT_TYPE_OFFSET                (2)
#define ETHER_TYPE_TYPE_OFFSET              (2)
#define UPDATE_BEACON_TYPE_OFFSET           (2)

#define XPAN_CHECK_SSID_LENGTH(x)  ((x >= GATT_XPAN_SERVER_MIN_SSID_SIZE) && (x <= GATT_XPAN_SERVER_MAX_SSID_SIZE))
#define XPAN_CHECK_SECURITY_MODE(x) x <= XPAN_SECURITY_MODE_UNKNOWN

/* Helper functions */
void xpanServerRespondToCharacteristicRead(CsrBtGattDbAccessReadInd *readInd, uint8 *value, uint16 valueLength, CsrBtGattId gattId)
{
    if (value != NULL)
    {
        if (readInd->offset > valueLength)
        {
            xpanServerSendAccessRsp(gattId,
                                    readInd->btConnId,
                                    readInd->attrHandle,
                                    CSR_BT_GATT_ACCESS_RES_INVALID_OFFSET,
                                    0,
                                    NULL);
        }
        else if(readInd->offset == valueLength)
        {
            xpanServerSendAccessRsp(gattId,
                                    readInd->btConnId,
                                    readInd->attrHandle,
                                    CSR_BT_GATT_ACCESS_RES_SUCCESS,
                                    0,
                                    NULL);
        }
        else
        {
            const uint8* dataPtr  = value;
            const uint8* lastPtr  = value + valueLength;
            uint16 sizeToSend     = valueLength;
            uint8 *truncatedValue = NULL;

            if (readInd->offset == 0 && valueLength <= readInd->maxRspValueLength)
            {
                /* Zero copy of value, removes the need for extra free and copy */
                truncatedValue = value;
            }
            else
            {
                /* Long read is being performed */
                sizeToSend = (valueLength - readInd->offset) > (readInd->maxRspValueLength) ?
                             (readInd->maxRspValueLength) : (valueLength - readInd->offset);
                dataPtr += readInd->offset;

                /* Allocate buffer memory, copy data from offset and free original pointer */
                truncatedValue = (uint8*)CsrPmemZalloc(sizeof(uint8)*sizeToSend);
                SynMemCpyS(truncatedValue, sizeToSend, dataPtr, lastPtr - dataPtr);
                pfree(value);

                GATT_XPAN_SERVER_INFO("xpanServerRespondToCharacteristicRead: characteristicValueLength %d, sizeToSend %d, maxRspLength %d, offset %d, truncatedValue %p",
                                        valueLength, sizeToSend, readInd->maxRspValueLength, readInd->offset, truncatedValue);
            }

            xpanServerSendAccessRsp(gattId,
                                    readInd->btConnId,
                                    readInd->attrHandle,
                                    CSR_BT_GATT_RESULT_SUCCESS,
                                    sizeToSend,
                                    truncatedValue);
        }
    }
    else
    {
        xpanServerSendAccessRsp(gattId,
                                readInd->btConnId,
                                readInd->attrHandle,
                                CSR_BT_GATT_ACCESS_RES_UNLIKELY_ERROR,
                                valueLength,
                                value);
    }
}

bool xpanValidateIteratorBufferUsage(GattAccessWriteIndIterator *iter)
{
    /* Check whether there were enough octets or not enough */
    if(GATT_BUFF_ITERATOR_ERROR_DETECTED(iter) == FALSE &&
       iter->bufferIndex == iter->accessInd->writeUnitCount &&
       iter->offset == 0)
    {
        return TRUE;
    }

    return FALSE;
}

uint16 xpanGetIteratorBufferRemainingSize(GattAccessWriteIndIterator *iter)
{
    uint16 size = 0;
    uint8 i = 0;

    /* Check whether there were enough octets or not enough */
    if(GATT_BUFF_ITERATOR_ERROR_DETECTED(iter) == FALSE )
    {
        size += (iter->accessInd->writeUnit[iter->bufferIndex].valueLength - iter->offset) ;

        if (iter->bufferIndex < iter->accessInd->writeUnitCount)
        {
            for (i = (iter->bufferIndex + 1); i < iter->accessInd->writeUnitCount; i++)
                size += iter->accessInd->writeUnit[i].valueLength;
        }
    }

    return size;
}

void xpanServerCpyArrayFromIterator(uint8 *dest, GattAccessWriteIndIterator* iter, uint16 len)
{
/*! TODO: optimise this to use SynMemCpyS instead of reading 8-by-8*/
    int i;
    for (i = 0; i < len; i++)
    {
        dest[i] = GattAccessIndIteratorRead8(iter);
        if (iter->error)
        {
            return;
        }
    }
}

void xpanCharacteristicReadResponse8(CsrBtGattDbAccessReadInd *readInd, uint8 data, CsrBtGattId gattId)
{
    uint8 *value = (uint8 *)CsrPmemAlloc(sizeof(uint8));

    value[0] = data;
    xpanServerSendAccessRsp(gattId, readInd->btConnId, readInd->attrHandle, CSR_BT_GATT_RESULT_SUCCESS, sizeof(uint8), value);
}

void xpanCharacteristicReadResponse16(CsrBtGattDbAccessReadInd *readInd, uint16 data, CsrBtGattId gattId)
{
    uint8 *value = (uint8 *)CsrPmemAlloc(sizeof(uint16));

    value[0] = (data & 0x00FF);
    value[1] = ((data >> 0x08) & 0x00FF);
    xpanServerSendAccessRsp(gattId, readInd->btConnId, readInd->attrHandle, CSR_BT_GATT_RESULT_SUCCESS, sizeof(uint16), value);
}

void xpanCharacteristicReadResponse32(CsrBtGattDbAccessReadInd *readInd, uint32 data, CsrBtGattId gattId)
{
    uint8 *value = (uint8 *)CsrPmemAlloc(sizeof(uint32));

    value[0] = data;
    value[1] = data >> 8;
    value[2] = data >> 16;
    value[3] = data >> 24;
    xpanServerSendAccessRsp(gattId, readInd->btConnId, readInd->attrHandle, CSR_BT_GATT_RESULT_SUCCESS, sizeof(uint32), value);
}

Bool xpanFindCid(CsrCmnListElm_t *elem, void *value)
{
    XpanClientDataElement *conn = (XpanClientDataElement *)elem;
    ConnectionId cid = *(ConnectionId *) value;
    return ((conn->clientData.cid == cid) ? TRUE : FALSE);
}

XpanClientDataElement *xpanFindClient(CsrCmnList_t *connectedClients, ConnectionId cid)
{
    XpanClientDataElement *client;

    for(client = (XpanClientDataElement *)connectedClients->first; client; client = client->next)
    {
        if(client->clientData.cid == cid)
        {
            return client;
        }
    }

    GATT_XPAN_SERVER_ERROR("XPAN Server: Client not found");
    return NULL;
}

static void xpanServerSendChangedTwtConfigurationInd(GattXpanServerData *const gattXpanServerInstance,
                                                      ConnectionId cid)
{
    MAKE_XPAN_MESSAGE(GattXpanServerTwtConfigurationInd);

    XpanClientDataElement *client = xpanFindClient(&gattXpanServerInstance->data.connectedClients, cid);

    if(client)
    {
        message->xpanServiceHandle = gattXpanServerInstance->serviceHandle;
        message->cid = cid;
        message->twtConfig = client->clientData.twtConfig;

        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_TWT_CONFIGURATION_IND, message);
    }
}

/****************************************************************
 * NAME
 *      xpanServerHandleTwtConfigurationAccess
 *
 * DESCRIPTION
 *      Deals with access of the HANDLE_TWT_CONFIGURATION handle.
 * **************************************************************/
void xpanServerHandleTwtConfigurationAccess(
        GattXpanServerData *gattXpanServerInstance,
        CsrBtGattDbAccessWriteInd *const accessInd)
{
    XpanClientDataElement *client = xpanFindClient(&gattXpanServerInstance->data.connectedClients, accessInd->btConnId);

    if (client)
    {
        if(accessInd->writeUnit == NULL)
        {
            /* 0 length means terminating of session */
            MAKE_XPAN_MESSAGE(GattXpanServerTwtConfigurationInd);
            /* Set characteristic to 0 */
            CsrMemSet(&(client->clientData.twtConfig), 0, sizeof(TwtConfiguration));
            message->xpanServiceHandle = gattXpanServerInstance->serviceHandle;
            message->cid = client->clientData.cid;

            xpanServerWriteGenericResponse(gattXpanServerInstance->gattId,
                                                accessInd->btConnId,
                                                CSR_BT_GATT_RESULT_SUCCESS,
                                                accessInd->attrHandle);

            XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_TWT_CONFIGURATION_IND, message);

            return;
        }
        else
        {
            GattAccessWriteIndIterator iter;
            uint32 temp = 0;
            uint8  setupId = 0;
            uint8  bitfield = 0;
            GattAccessIndIteratorInitialise(&iter, accessInd);

            setupId = GattAccessIndIteratorRead8(&iter);
            bitfield = GattAccessIndIteratorRead8(&iter);
            if((setupId != 0) && XPAN_SERVER_CHECK_BITS_VALID(bitfield, XPAN_SERVER_TWT_CONFIG_BITFIELD_VALID_BITS))
            {
                client->clientData.twtConfig.setupId = setupId;
                client->clientData.twtConfig.bitfield = bitfield;
                client->clientData.twtConfig.desiredWakeDuration = GattAccessIndIteratorRead32(&iter);
                client->clientData.twtConfig.desiredWakeInterval = GattAccessIndIteratorRead32(&iter);
                temp = GattAccessIndIteratorRead8(&iter) << 0x18;
                temp += GattAccessIndIteratorRead8(&iter) << 0x10;
                temp += GattAccessIndIteratorRead8(&iter) << 0x08;
                temp += GattAccessIndIteratorRead8(&iter);
                client->clientData.twtConfig.desiredWakeTsfLeft[0] = temp;
                temp = GattAccessIndIteratorRead8(&iter) << 0x18;
                temp += GattAccessIndIteratorRead8(&iter) << 0x10;
                temp += GattAccessIndIteratorRead8(&iter) << 0x08;
                temp += GattAccessIndIteratorRead8(&iter);
                client->clientData.twtConfig.desiredWakeTsfLeft[1] = temp;
                client->clientData.twtConfig.desiredWakeTsfRightOffset = GattAccessIndIteratorRead32(&iter);

                if(xpanValidateIteratorBufferUsage(&iter))
                {
                    xpanServerWriteGenericResponse(gattXpanServerInstance->gattId,
                                                    accessInd->btConnId,
                                                    CSR_BT_GATT_RESULT_SUCCESS,
                                                    accessInd->attrHandle);

                    xpanServerSendChangedTwtConfigurationInd(gattXpanServerInstance, accessInd->btConnId);
                }
                else
                {
                    GATT_XPAN_SERVER_ERROR("HANDLE_TWT_CONFIGURATION: CSR_BT_GATT_RESULT_INVALID_LENGTH\n");
                    xpanServerSendAccessErrorRsp(
                        gattXpanServerInstance->gattId,
                        accessInd->btConnId,
                        accessInd->attrHandle,
                        CSR_BT_GATT_RESULT_INVALID_LENGTH);
                }
            }
            else
            {
                GATT_XPAN_SERVER_ERROR("HANDLE_TWT_CONFIGURATION: CSR_BT_GATT_RESULT_INVALID_PARAMETER\n");
                xpanServerSendAccessErrorRsp(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    CSR_BT_GATT_RESULT_UNACCEPTABLE_PARAMETER);
            }
        }
    }
    else
    {
        GATT_XPAN_SERVER_ERROR("HANDLE_TWT_CONFIGURATION: CSR_BT_GATT_RESULT_UNKNOWN_CONN_ID\n");
        xpanServerSendAccessErrorRsp(
            gattXpanServerInstance->gattId,
            accessInd->btConnId,
            accessInd->attrHandle,
            CSR_BT_GATT_RESULT_UNKNOWN_CONN_ID);
    }
}

/****************************************************************
 * NAME
 *      xpanServerHandleClearToSendRead
 *
 * DESCRIPTION
 *      Deals with read access of the HANDLE_CLEAR_TO_SEND handle.
 * **************************************************************/
void xpanServerHandleClearToSendRead(
        GattXpanServerData *gattXpanServerInstance,
        CsrBtGattDbAccessReadInd *const accessInd)
{
    XpanClientDataElement *client = xpanFindClient(&gattXpanServerInstance->data.connectedClients, accessInd->btConnId);

    if(client)
    {
        GattBuffIterator iter;
        uint16 valueLength = sizeof(uint8)*GATT_XPAN_SERVER_CLEAR_TO_SEND_SIZE;
        uint8 *value = (uint8 *)CsrPmemAlloc(valueLength);

        GattBuffIteratorInitialise(&iter, value, valueLength);

        GattBuffIteratorWrite8(&iter, client->clientData.clearToSend);
        xpanServerRespondToCharacteristicRead(accessInd, value, valueLength, gattXpanServerInstance->gattId);
    }
}

uint8 xpanServerConnectSsidHandle(GattXpanServerData *gattXpanServerInstance,
                                  GattAccessWriteIndIterator *accessIndIter)
{
    /* The format for Connect Ssid is:
     *  value[0] = 0x01 GATT_XPAN_SERVER_CONNECT_SSID_OPCODE
     *  value[1] -> ssidLength
     *  value[2] -> ssid[0]
     *  ...
     *  value[2+ssidLength-1] -> ssid[ssidLength-1]
     *  ...
     *  value[2+ssidLength] -> passPhraseLength
     *  value[2+ssidLength+1] -> passPhrase[0]
     *  ...
     *  value[2+ssidLength+2] -> passPhrase[passPhraseLength]
     *  ...
     *  value[4+ssidLength+passPhraseLength-1] -> bssid
     *  value[10+ssidLength+passPhraseLength-1] -> center frequency
     *  value[11+ssidLength+passPhraseLength] -> securityMode
     *  value[12+ssidLength+passPhraseLength] -> countryString
     *  value[15+ssidLength+passPhraseLength] -> pmk if present
     */
    uint8 result = CSR_BT_GATT_ACCESS_RES_SUCCESS;
    GattXpanConnectSsidInd *message = (GattXpanConnectSsidInd *)CsrPmemZalloc(sizeof(GattXpanConnectSsidInd));

    message->cid = accessIndIter->accessInd->btConnId;

    message->connectSsid.ssidLength = GattAccessIndIteratorRead8(accessIndIter);
    if (XPAN_CHECK_SSID_LENGTH(message->connectSsid.ssidLength))
    {
        message->connectSsid.ssid = GattAccessIndIteratorReadMultipleOctets(accessIndIter, message->connectSsid.ssidLength);
        message->passphraseLength = GattAccessIndIteratorRead8(accessIndIter);
        if (((message->passphraseLength >= GATT_XPAN_SERVER_MIN_PASSPHRASE_LENGTH_SIZE) &&
            (message->passphraseLength <= GATT_XPAN_SERVER_MAX_PASSPHRASE_LENGTH_SIZE)) ||
            (message->passphraseLength == 0))
        {
            message->passPhrase = GattAccessIndIteratorReadMultipleOctets(accessIndIter, message->passphraseLength);
            xpanServerCpyArrayFromIterator(message->bssid, accessIndIter, GATT_XPAN_SERVER_BSSID_SIZE);
            message->primaryFrequency = GattAccessIndIteratorRead16(accessIndIter);
            message->securityMode = GattAccessIndIteratorRead8(accessIndIter);

            if((message->securityMode == XPAN_SECURITY_MODE_OPEN && message->passphraseLength == 0) ||
                (message->securityMode != XPAN_SECURITY_MODE_OPEN && message->passphraseLength != 0))
            {
                if (message->securityMode <= XPAN_SECURITY_MODE_UNKNOWN)
                {
                    xpanServerCpyArrayFromIterator(message->countryString, accessIndIter, GATT_XPAN_SERVER_COUNTRY_STRING_SIZE);

                    if (xpanGetIteratorBufferRemainingSize(accessIndIter) == GATT_XPAN_SERVER_PMK_SIZE)
                        message->pmk = GattAccessIndIteratorReadMultipleOctets(accessIndIter, GATT_XPAN_SERVER_PMK_SIZE);

                    if (xpanValidateIteratorBufferUsage(accessIndIter) == TRUE)
                    {
                        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_CONNECT_SSID_IND, message);
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - Connect ssid operation: invalid length\n");
                        GattXpanServerFreeControlPointMessageContents(message);
                        pfree(message);
                        result = GATT_XPAN_INVALID_LENGTH;
                    }
                }
                else
                {
                    GATT_XPAN_SERVER_ERROR("Error - Connect ssid operation: invalid security mode\n");
                    GattXpanServerFreeControlPointMessageContents(message);
                    pfree(message);
                    result = GATT_XPAN_INVALID_DATA;
                }
            }
            else
            {
                GATT_XPAN_SERVER_ERROR("Error - Connect ssid operation: invalid passphrase length and security mode pair\n");
                GattXpanServerFreeControlPointMessageContents(message);
                pfree(message);
                result = GATT_XPAN_INVALID_DATA;
            }

        }
        else
        {
            GATT_XPAN_SERVER_ERROR("Error - Connect ssid operation: invalid passphrase length\n");
            GattXpanServerFreeControlPointMessageContents(message);
            pfree(message);
            result = GATT_XPAN_INVALID_DATA;
        }
    }
    else
    {
        GATT_XPAN_SERVER_ERROR("Error - Connect ssid operation: invalid ssid length\n");
        result = GATT_XPAN_INVALID_LENGTH;
        pfree(message);
    }

    return result;
}

uint8 xpanServerConnectedSsidHandle(GattXpanServerData *gattXpanServerInstance,
                                    GattAccessWriteIndIterator *accessIndIter)
{
    /* The format for Connected Ssid is:
     *  value[0] = 0x03 GATT_XPAN_SERVER_CONNECTED_SSID_OPCODE
     *  value[1] -> ssidLength
     *  value[2] -> ssid[0]
     *  ...
     *  value[2+ssidLength-1] -> ssid[ssidLength-1]
     *  ....
     *  value[2+ssidLength] -> bssid
     *  value[8+ssidLength] -> center frequency
     *  value[9+ssidLength] -> ipv4Address
     *  value[13+ssidLength] -> ipv6Address
     *  value[29+ssidLength] -> Mac address
     *  value[35+ssidLength] -> Passphrase length
     *  value[36+ssidLength] to [36+ssidLength + passphraseLength-1] -> Passphrase
     *  value[36+ssidLength + passphraseLength] -> Security Mode
     *  value[37+ssidLength + passphraseLength] -> Country String
     *  value[40+ssidLength + passphraseLength] -> pmk if present
     */
    uint8 result = CSR_BT_GATT_ACCESS_RES_SUCCESS;
    GattXpanConnectedSsidInd *message = (GattXpanConnectedSsidInd *)CsrPmemZalloc(sizeof(GattXpanConnectedSsidInd));
    uint8 i;

    message->cid = accessIndIter->accessInd->btConnId;
    message->connectedSsid.ssidLength = GattAccessIndIteratorRead8(accessIndIter);
    if (XPAN_CHECK_SSID_LENGTH(message->connectedSsid.ssidLength))
    {
        message->connectedSsid.ssid = GattAccessIndIteratorReadMultipleOctets(accessIndIter, message->connectedSsid.ssidLength);
        xpanServerCpyArrayFromIterator(message->bssid, accessIndIter, GATT_XPAN_SERVER_BSSID_SIZE);
        message->primaryFrequency = GattAccessIndIteratorRead16(accessIndIter);
        xpanServerCpyArrayFromIterator(message->ipv4Address, accessIndIter, XPAN_SERVER_IPV4_ADDRESS_SIZE);
        xpanServerCpyArrayFromIterator(message->ipv6Address, accessIndIter, XPAN_SERVER_IPV6_ADDRESS_SIZE);
        xpanServerCpyArrayFromIterator(message->macAddress, accessIndIter, GATT_XPAN_SERVER_MAC_ADDRESS_SIZE);

        message->passphrase.length = GattAccessIndIteratorRead8(accessIndIter);

        /* The passphrase must always be shorter than or equal to the maximum length */
        if (message->passphrase.length > GATT_XPAN_SERVER_PASSPHRASE_MAX_LENGTH)
        {
            GATT_XPAN_SERVER_WARNING("Warning - Connected ssid operation: invalid passphrase length\n");
            GattXpanServerFreeControlPointMessageContents(message);
            pfree(message);
            return GATT_XPAN_INVALID_DATA;
        }
        message->passphrase.value = GattAccessIndIteratorReadMultipleOctets(accessIndIter, message->passphrase.length);
        message->securityMode = GattAccessIndIteratorRead8(accessIndIter);

        if (message->securityMode <= XPAN_SECURITY_MODE_UNKNOWN)
        {
            if (message->securityMode == XPAN_SECURITY_MODE_OPEN)
            {   /* 'Open' security mode shall have zero length passphrase */
                if (message->passphrase.length != 0)
                {
                    GATT_XPAN_SERVER_WARNING("Warning - Connected ssid operation: invalid passphrase length for Open Security\n");
                    GattXpanServerFreeControlPointMessageContents(message);
                    pfree(message);
                    return GATT_XPAN_INVALID_DATA;
                }
            }
            else
            {   /* The security mode is not 'Open', so the passphrase must be longer than or equal to the minimum length */
                if (message->passphrase.length < GATT_XPAN_SERVER_PASSPHRASE_MIN_LENGTH)
                {
                    GATT_XPAN_SERVER_WARNING("Warning - Connected ssid operation: invalid passphrase length\n");
                    GattXpanServerFreeControlPointMessageContents(message);
                    pfree(message);
                    return GATT_XPAN_INVALID_DATA;
                }
            }
            for (i = 0; i < GATT_XPAN_SERVER_COUNTRY_STRING_SIZE; i++)
            {
                message->countryString[i] = GattAccessIndIteratorRead8(accessIndIter);
            }

            if (xpanGetIteratorBufferRemainingSize(accessIndIter) == GATT_XPAN_SERVER_PMK_SIZE)
                message->pmk = GattAccessIndIteratorReadMultipleOctets(accessIndIter, GATT_XPAN_SERVER_PMK_SIZE);

            if (xpanValidateIteratorBufferUsage(accessIndIter) == TRUE)
            {
                XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_CONNECTED_SSID_IND, message);
            }
            else
            {
                GATT_XPAN_SERVER_ERROR("Error - Connected ssid operation: invalid length\n");
                GattXpanServerFreeControlPointMessageContents(message);
                pfree(message);
                result = GATT_XPAN_INVALID_LENGTH;
            }
        }
        else
        {
            GATT_XPAN_SERVER_ERROR("Error - Connected ssid operation: invalid security mode\n");
            result = GATT_XPAN_INVALID_DATA;
            GattXpanServerFreeControlPointMessageContents(message);
            pfree(message);
        }

    }
    else
    {
        GATT_XPAN_SERVER_ERROR("Error - Connected ssid operation: invalid ssid length\n");
        result = GATT_XPAN_INVALID_LENGTH;
        pfree(message);
    }

    return result;
}

uint8 xpanServerAvailableSsidHandle(GattXpanServerData *gattXpanServerInstance,
                                    GattAccessWriteIndIterator *accessIndIter)
{
    /* The format for Available ssid:
     *  value[0] = 0x04 GATT_XPAN_SERVER_AVAILABLE_SSID_OPCODE
     *  value[1] -> ssidLength
     *  value[2] -> ssid[0]
     *  ...
     *  value[2+ssidLength-1] -> ssid[ssidLength-1]
     *  ...
     *  value[2+ssidLength] -> passPhraseLength
     *  value[2+ssidLength+1] -> passPhrase[0]
     *  ...
     *  value[2+ssidLength+2] -> passPhrase[passPhraseLength]
     *  ...
     *  value[2+ssidLength+3] -> securityMode
     *  value[2+ssidLength+4] -> numBssids
     *  ...
     *  value[...] - value[...] -> BssidData[numBssids-1]
     *  value[2+ssidLength+5+bssidDataLen] -> pmk if present
     */
    uint8 i;
    uint8 result = CSR_BT_GATT_ACCESS_RES_SUCCESS;
    GattXpanAvailableSsidInd *message = (GattXpanAvailableSsidInd *)CsrPmemZalloc(sizeof(GattXpanAvailableSsidInd));

    message->cid = accessIndIter->accessInd->btConnId;
    message->availableSsid.ssidLength = GattAccessIndIteratorRead8(accessIndIter);
    if (XPAN_CHECK_SSID_LENGTH(message->availableSsid.ssidLength))
    {
        message->availableSsid.ssid = GattAccessIndIteratorReadMultipleOctets(accessIndIter, message->availableSsid.ssidLength);
        message->passphraseLength = GattAccessIndIteratorRead8(accessIndIter);
        if(((message->passphraseLength >= GATT_XPAN_SERVER_MIN_PASSPHRASE_LENGTH_SIZE) &&
            (message->passphraseLength <= GATT_XPAN_SERVER_MAX_PASSPHRASE_LENGTH_SIZE)) ||
            (message->passphraseLength == 0))
        {
            message->passphrase = GattAccessIndIteratorReadMultipleOctets(accessIndIter, message->passphraseLength);
            message->securityMode = GattAccessIndIteratorRead8(accessIndIter);

            if((message->securityMode == XPAN_SECURITY_MODE_OPEN && message->passphraseLength == 0) ||
                (message->securityMode != XPAN_SECURITY_MODE_OPEN && message->passphraseLength != 0))
            {
                if (message->securityMode <= XPAN_SECURITY_MODE_UNKNOWN)
                {
                    message->numBssid = GattAccessIndIteratorRead8(accessIndIter);
                    if (message->numBssid)
                    {
                        message->bssidData = (Bssid *)CsrPmemZalloc(sizeof(Bssid) * message->numBssid);

                        for (i = 0; i < message->numBssid; i++)
                        {
                            xpanServerCpyArrayFromIterator(message->bssidData[i].bssid, accessIndIter, GATT_XPAN_SERVER_BSSID_SIZE);
                            message->bssidData[i].primaryFrequency = GattAccessIndIteratorRead16(accessIndIter);
                        }
                    }

                    if (xpanGetIteratorBufferRemainingSize(accessIndIter) == GATT_XPAN_SERVER_PMK_SIZE)
                        message->pmk = GattAccessIndIteratorReadMultipleOctets(accessIndIter, GATT_XPAN_SERVER_PMK_SIZE);

                    if (xpanValidateIteratorBufferUsage(accessIndIter) == TRUE)
                    {
                        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_AVAILABLE_SSID_IND, message);
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - Available ssid operation: invalid length\n");
                        GattXpanServerFreeControlPointMessageContents(message);
                        pfree(message);
                        result = GATT_XPAN_INVALID_LENGTH;
                    }
                }
                else
                {
                    GATT_XPAN_SERVER_ERROR("Error - Available ssid operation: invalid security mode\n");
                    GattXpanServerFreeControlPointMessageContents(message);
                    pfree(message);
                    result = GATT_XPAN_INVALID_DATA;
                }
            }
            else
            {
                GATT_XPAN_SERVER_ERROR("Error - Available ssid operation: invalid passphrase length and security mode pair\n");
                GattXpanServerFreeControlPointMessageContents(message);
                pfree(message);
                result = GATT_XPAN_INVALID_DATA;
            }
        }
        else
        {
            GATT_XPAN_SERVER_ERROR("Error - Available ssid operation: invalid passphrase length\n");
            GattXpanServerFreeControlPointMessageContents(message);
            pfree(message);
            result = GATT_XPAN_INVALID_DATA;
        }
    }
    else
    {
        GATT_XPAN_SERVER_ERROR("Error - Available ssid operation: invalid ssid length\n");
        result = GATT_XPAN_INVALID_LENGTH;
        pfree(message);
    }

    return result;
}

uint8 xpanServerRelatedSsidsHandle(GattXpanServerData *gattXpanServerInstance,
                                   GattAccessWriteIndIterator *accessIndIter)
{
    /* The format for related ssids:
     *  value[0] = 0x05 GATT_XPAN_SERVER_RELATED_SSIDS_OPCODE
     *  value[1] -> numSsids
     *  value[2] -> ssid[0]
     *  ...
     *  value[...] - value[...] -> ssid[numSsids-1]
     */
    uint8 i;
    uint8 result = CSR_BT_GATT_ACCESS_RES_SUCCESS;
    GattXpanRelatedSsidInd *message = (GattXpanRelatedSsidInd *)CsrPmemZalloc(sizeof(GattXpanRelatedSsidInd));

    message->cid = accessIndIter->accessInd->btConnId;
    message->numSsids = GattAccessIndIteratorRead8(accessIndIter);

    if (message->numSsids)
    {
        message->relatedSsid = (SsidData *)CsrPmemZalloc(sizeof(SsidData) * message->numSsids);

        for (i = 0; i < message->numSsids; i++)
        {
            message->relatedSsid[i].ssidLength = GattAccessIndIteratorRead8(accessIndIter);
            if (XPAN_CHECK_SSID_LENGTH(message->relatedSsid[i].ssidLength))
            {
                message->relatedSsid[i].ssid = GattAccessIndIteratorReadMultipleOctets(accessIndIter, message->relatedSsid[i].ssidLength);
            }
            else
            {
                uint8 ssidCount;
                GATT_XPAN_SERVER_ERROR("Error - Related ssids operation: invalid parameters\n");
                result = GATT_XPAN_INVALID_DATA;
                /* Free memory for allocated for ssids. */
                for (ssidCount = 0; ssidCount < i; ssidCount++)
                    pfree(message->relatedSsid[ssidCount].ssid);
                pfree(message->relatedSsid);
                pfree(message);

                GATT_XPAN_SERVER_ERROR("Error - Related ssid operation: invalid length\n");
                result = GATT_XPAN_INVALID_LENGTH;

                return result;
            }
        }
    }

    if(accessIndIter->bufferIndex != accessIndIter->accessInd->writeUnitCount ||
            accessIndIter->offset != 0 ||
            GATT_BUFF_ITERATOR_ERROR_DETECTED(accessIndIter) == TRUE)
    {
        GattXpanServerFreeControlPointMessageContents(message);
        pfree(message);
        result = GATT_XPAN_INVALID_LENGTH;
    }
    else
    {
        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_RELATED_SSID_IND, message);
    }

    return result;
}

uint8 xpanServerConnectedEnterpriseSsidHandle(GattXpanServerData *gattXpanServerInstance,
                                              GattAccessWriteIndIterator *accessIndIter)
{
    /* The format for Connected Enterprise Ssid is:
     *  value[0] = 0x1C GATT_XPAN_SERVER_CONNECTED_ENTERPRISE_SSID_OPCODE
     *  value[1] -> ssidLength
     *  value[2] -> ssid[0]
     *  ...
     *  value[2+ssidLength-1] -> ssid[ssidLength-1]
     *  ....
     *  value[2+ssidLength] -> bssid
     *  value[8+ssidLength] -> center frequency
     *  value[9+ssidLength] -> ipv4Address
     *  value[13+ssidLength] -> ipv6Address
     *  value[29+ssidLength] -> Mac address
     *  value[35+ssidLength] -> identity length
     *  value[36+ssidLength] to [36+ssidLength + identityLength-1] -> identity
     *  value[36+ssidLength + identitiyLength] -> password length
     *  value[37+ssidLength + identitiyLength] to [37+ssidLength + identityLength + passwordLength-1] -> password
     *  value[37+ssidLength + identityLength + passwordLength] -> Security Mode
     *  value[38+ssidLength + identityLength + passwordLength] -> Country String
     */
    uint8 result = CSR_BT_GATT_ACCESS_RES_SUCCESS;
    GattXpanConnectedEnterpriseSsidInd *message = (GattXpanConnectedEnterpriseSsidInd *)CsrPmemZalloc(sizeof(GattXpanConnectedEnterpriseSsidInd));
    uint8 i;

    message->cid = accessIndIter->accessInd->btConnId;
    message->connectedEnterpriseSsid.ssidLength = GattAccessIndIteratorRead8(accessIndIter);
    if (XPAN_CHECK_SSID_LENGTH(message->connectedEnterpriseSsid.ssidLength))
    {
        message->connectedEnterpriseSsid.ssid = GattAccessIndIteratorReadMultipleOctets(accessIndIter, message->connectedEnterpriseSsid.ssidLength);
        xpanServerCpyArrayFromIterator(message->bssId, accessIndIter, GATT_XPAN_SERVER_BSSID_SIZE);
        message->primaryFrequency = GattAccessIndIteratorRead16(accessIndIter);
        xpanServerCpyArrayFromIterator(message->ipv4Address, accessIndIter, XPAN_SERVER_IPV4_ADDRESS_SIZE);
        xpanServerCpyArrayFromIterator(message->ipv6Address, accessIndIter, XPAN_SERVER_IPV6_ADDRESS_SIZE);
        xpanServerCpyArrayFromIterator(message->macAddress, accessIndIter, GATT_XPAN_SERVER_MAC_ADDRESS_SIZE);

        message->identity.length = GattAccessIndIteratorRead8(accessIndIter);
        message->identity.value = GattAccessIndIteratorReadMultipleOctets(accessIndIter, message->identity.length);

        message->password.length = GattAccessIndIteratorRead8(accessIndIter);

        /* The password can have a max length of 255 which is taken care by the type uint8 itself. No need to validate */
        message->password.value = GattAccessIndIteratorReadMultipleOctets(accessIndIter, message->password.length);
        message->securityMode = GattAccessIndIteratorRead8(accessIndIter);

        if (message->securityMode < XPAN_ENTERPRISE_SECURITY_MODE_MIN_RESERVED_VALUE)
        {
            for (i = 0; i < GATT_XPAN_SERVER_COUNTRY_STRING_SIZE; i++)
            {
                message->countryString[i] = GattAccessIndIteratorRead8(accessIndIter);
            }

            if (xpanValidateIteratorBufferUsage(accessIndIter) == TRUE)
            {
                XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_CONNECTED_ENTERPRISE_SSID_IND, message);
            }
            else
            {
                GATT_XPAN_SERVER_ERROR("Error - Connected Enterprise ssid operation: invalid length\n");
                GattXpanServerFreeControlPointMessageContents(message);
                pfree(message);
                result = GATT_XPAN_INVALID_LENGTH;
            }
        }
        else
        {
            GATT_XPAN_SERVER_ERROR("Error - Connected Enterprise ssid operation: invalid security mode\n");
            result = GATT_XPAN_INVALID_DATA;
            GattXpanServerFreeControlPointMessageContents(message);
            pfree(message);
        }
    }
    else
    {
        GATT_XPAN_SERVER_ERROR("Error - Connected Enterprise ssid operation: invalid ssid length\n");
        result = GATT_XPAN_INVALID_LENGTH;
        pfree(message);
    }

    return result;
}


/****************************************************************
 * NAME
 *      xpanServerHandleXpanControlPointWrite
 *
 * DESCRIPTION
 *      Deals with write access of the HANDLE_XPAN_CONTROL_POINT handle.
 * **************************************************************/
void xpanServerHandleXpanControlPointWrite(
    GattXpanServerData *gattXpanServerInstance,
    CsrBtGattDbAccessWriteInd *const accessInd)
{
    uint8 i;
    uint16 length = 0;
    GattAccessWriteIndIterator iter;
    uint16 result = CSR_BT_GATT_ACCESS_RES_SUCCESS;

    if (accessInd)
    {
        if (!(accessInd->writeUnit))
        {
            /* Respond to empty ATT permission write*/
            xpanServerSendAccessRsp(gattXpanServerInstance->gattId,
                                    accessInd->btConnId,
                                    accessInd->attrHandle,
                                    CSR_BT_GATT_ACCESS_RES_SUCCESS,
                                    0,
                                    NULL);
            return;
        }
        else
        {
            for (i = 0; i < accessInd->writeUnitCount; i++)
            {
                length += accessInd->writeUnit[i].valueLength;
            }

            GattAccessIndIteratorInitialise(&iter, accessInd);

            uint8 opcode = GattAccessIndIteratorRead8(&iter);

            switch (opcode)
            {
                case GATT_XPAN_SERVER_CONNECT_SSID_OPCODE:
                {
                    /* The format for Connect Ssid is:
                    *  value[0] = 0x01 GATT_XPAN_SERVER_CONNECT_SSID_OPCODE
                    *  value[1] -> ssidLength
                    *  value[2] -> ssid[0]
                    *  ...
                    *  value[2+ssidLength-1] -> ssid[ssidLength-1]
                    *  ...
                    *  value[2+ssidLength] -> passPhraseLength
                    *  value[2+ssidLength+1] -> passPhrase[0]
                    *  ...
                    *  value[2+ssidLength+2] -> passPhrase[passPhraseLength]
                    *  ...
                    *  value[4+ssidLength+passPhraseLength-1] -> bssid
                    *  value[10+ssidLength+passPhraseLength-1] -> channelNumber
                    *  value[10+ssidLength+passPhraseLength] -> securityMode
                    */
                    result = xpanServerConnectSsidHandle(gattXpanServerInstance, &iter);
                    break;
                }
                case GATT_XPAN_SERVER_DISCONNECT_SSID_OPCODE:
                {
                    GattXpanDisconnectSsidInd *message = (GattXpanDisconnectSsidInd *)CsrPmemZalloc(sizeof(GattXpanDisconnectSsidInd));

                    message->cid = iter.accessInd->btConnId;
                    message->disconnectSsid.ssidLength = GattAccessIndIteratorRead8(&iter);

                    /* Ensure length of ssid is valid */
                    if (XPAN_CHECK_SSID_LENGTH(message->disconnectSsid.ssidLength))
                    {
                        message->disconnectSsid.ssid = GattAccessIndIteratorReadMultipleOctets(&iter, message->disconnectSsid.ssidLength);

                        if (xpanValidateIteratorBufferUsage(&iter) == TRUE)
                        {
                            XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_DISCONNECT_SSID_IND, message);
                        }
                        else
                        {
                            GattXpanServerFreeControlPointMessageContents(message);
                            pfree(message);
                            GATT_XPAN_SERVER_ERROR("Error - Disconnect ssid operation: invalid length\n");
                            result = GATT_XPAN_INVALID_LENGTH;
                        }
                    }
                    else
                    {
                        pfree(message);
                        GATT_XPAN_SERVER_ERROR("Error - Disconnect ssid operation: invalid ssid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }

                    break;
                }
                case GATT_XPAN_SERVER_CONNECTED_SSID_OPCODE:
                {
                    /* Handle the write and alter result depending on the validation results*/
                    result = xpanServerConnectedSsidHandle(gattXpanServerInstance, &iter);
                    break;
                }
                case GATT_XPAN_SERVER_AVAILABLE_SSID_OPCODE:
                {
                    /* The format for Available ssid:
                    *  value[0] = 0x04 GATT_XPAN_SERVER_AVAILABLE_SSID_OPCODE
                    *  value[1] -> ssidLength
                    *  value[2] -> ssid[0]
                    *  ...
                    *  value[2+ssidLength-1] -> ssid[ssidLength-1]
                    *  ...
                    *  value[2+ssidLength] -> passPhraseLength
                    *  value[2+ssidLength+1] -> passPhrase[0]
                    *  ...
                    *  value[2+ssidLength+2] -> passPhrase[passPhraseLength]
                    *  ...
                    *  value[2+ssidLength+3] -> securityMode
                    *  value[2+ssidLength+4] -> numBssids
                    *  ...
                    *  value[...] - value[...] -> BssidData[numBssids-1]
                    */
                    result = xpanServerAvailableSsidHandle(gattXpanServerInstance, &iter);
                    break;
                }
                case GATT_XPAN_SERVER_RELATED_SSIDS_OPCODE:
                {
                    /* The format for related ssids:
                    *  value[0] = 0x05 GATT_XPAN_SERVER_RELATED_SSIDS_OPCODE
                    *  value[1] -> ssidLength
                    *  value[2] -> ssid[0]
                    *  ...
                    *  value[2+ssidLength-1] -> ssid[ssidLength-1]
                    */
                    result = xpanServerRelatedSsidsHandle(gattXpanServerInstance, &iter);
                    break;
                }
                case GATT_XPAN_SERVER_MDNS_SRV_UUID_OPCODE:
                {
                    /* The format for mDns Srv UUID is:
                    *  value[0] = 0x06 GATT_XPAN_SERVER_MDNS_SRV_UUID_OPCODE
                    *  value[1] - value[16] -> mDnsSrvUuid
                    */
                    if (length == GATT_XPAN_SERVER_MDNS_SRV_UUID_OPCODE_SIZE)
                    {
                        GattXpanMdnsSrvUuidInd *message = (GattXpanMdnsSrvUuidInd *)CsrPmemZalloc(sizeof(GattXpanMdnsSrvUuidInd));

                        message->cid = accessInd->btConnId;
                        xpanServerCpyArrayFromIterator(message->mDnsSrvUuid, &iter, GATT_XPAN_SERVER_MDNS_SRV_UUID_SIZE);

                        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_MDNS_SRV_UUID_IND, message);
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - mDns Srv UUID operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }

                    break;
                }
                case GATT_XPAN_SERVER_REMOVE_SSID_OPCODE:
                {
                    /* The format for Remove SSID is:
                    *  value[0] = 0x07 GATT_XPAN_SERVER_REMOVE_SSID_OPCODE
                    *  value[1] = ssidLength
                    *  value[2] - value[ssidLength+2] -> ssid
                    */
                    GattXpanRemoveSsidInd *message = (GattXpanRemoveSsidInd *)CsrPmemZalloc(sizeof(GattXpanRemoveSsidInd));

                    message->removeSsid.ssidLength = GattAccessIndIteratorRead8(&iter);
                    if (XPAN_CHECK_SSID_LENGTH(message->removeSsid.ssidLength))
                    {
                        message->cid = accessInd->btConnId;
                        message->removeSsid.ssid = GattAccessIndIteratorReadMultipleOctets(&iter, message->removeSsid.ssidLength);
                        if (xpanValidateIteratorBufferUsage(&iter) == TRUE)
                        {
                            XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_REMOVE_SSID_IND, message);
                        }
                        else
                        {
                            GATT_XPAN_SERVER_ERROR("Error - Remove ssid operation: invalid length \n");
                            result = GATT_XPAN_INVALID_LENGTH;
                            pfree(message->removeSsid.ssid);
                            pfree(message);
                        }
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - Remove ssid operation: ssidLength invalid \n");
                        result = GATT_XPAN_INVALID_LENGTH;
                        pfree(message);
                    }

                    break;
                }
                case GATT_XPAN_SERVER_L2CAP_TCP_PORT_OPCODE:
                {
                    /* The format for L2cap TCP Port is:
                    *  value[0] = 0x08 GATT_XPAN_SERVER_L2CAP_TCP_PORT_OPCODE
                    *  value[1] - value[3] = l2capTcpPort
                    */
                    if (length == GATT_XPAN_SERVER_L2CAP_TCP_PORT_OPCODE_SIZE)
                    {
                        GattXpanL2capTcpPortInd *message = (GattXpanL2capTcpPortInd *)CsrPmemZalloc(sizeof(GattXpanL2capTcpPortInd));

                        message->cid = accessInd->btConnId;
                        message->l2capTcpPort = GattAccessIndIteratorRead16(&iter);

                        if (GATT_BUFF_ITERATOR_ERROR_DETECTED(&iter) != TRUE)
                        {
                            XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_L2CAP_TCP_PORT_IND, message);
                        }
                        else
                        {
                            pfree(message);
                            GATT_XPAN_SERVER_ERROR("Error - L2cap TCP port operation: unlikely error\n");
                            result = CSR_BT_GATT_ACCESS_RES_UNLIKELY_ERROR;
                        }
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - L2CAP TCP port operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }

                    break;
                }
                case GATT_XPAN_SERVER_UDP_PORT_OPCODE:
                {
                    /* The format for UDP Port is:
                    *  value[0] = 0x09 GATT_XPAN_SERVER_UDP_PORT_OPCODE
                    *  value[1] - value[2] = UdpPortAudio
                    *  value[3] - value[4] = UdpPortReports
                    */
                    if (length == GATT_XPAN_SERVER_UDP_PORT_OPCODE_SIZE)
                    {
                        GattXpanUdpPortInd *message = (GattXpanUdpPortInd *)CsrPmemZalloc(sizeof(GattXpanUdpPortInd));

                        message->cid = accessInd->btConnId;
                        message->udpPortAudio = GattAccessIndIteratorRead16(&iter);
                        message->udpPortReports = GattAccessIndIteratorRead16(&iter);

                        if (GATT_BUFF_ITERATOR_ERROR_DETECTED(&iter) != TRUE)
                        {
                            XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_UDP_PORT_IND, message);
                        }
                        else
                        {
                            pfree(message);
                            GATT_XPAN_SERVER_ERROR("Error - UDP port operation: unlikely error\n");
                            result = CSR_BT_GATT_ACCESS_RES_UNLIKELY_ERROR;
                        }
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - UDP PORT operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }
                    break;
                }
                case GATT_XPAN_SERVER_ETHER_TYPE_OPCODE:
                {
                    /* The format for Ether Type is:
                    *  value[0] = 0x0A GATT_XPAN_SERVER_ETHER_TYPE_OPCODE
                    *  value[1] - value[2] = etherType
                    */
                    if (length == GATT_XPAN_SERVER_ETHER_TYPE_OPCODE_SIZE)
                    {
                        GattXpanEtherTypeInd *message = (GattXpanEtherTypeInd *)CsrPmemZalloc(sizeof(GattXpanEtherTypeInd));

                        message->cid = accessInd->btConnId;
                        message->etherType = GattAccessIndIteratorRead16(&iter);

                        if (GATT_BUFF_ITERATOR_ERROR_DETECTED(&iter) != TRUE)
                        {
                            XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_ETHER_TYPE_IND, message);
                        }
                        else
                        {
                            GATT_XPAN_SERVER_ERROR("Error - Ether type operation: unlikely error\n");
                            result = CSR_BT_GATT_ACCESS_RES_UNLIKELY_ERROR;
                            pfree(message);
                        }
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - Ether type operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }
                    break;
                }
                case GATT_XPAN_SERVER_MAC_ADDRESS_OPCODE:
                {
                    /* The format for MAC Address is:
                    *  value[0] = 0x0B GATT_XPAN_SERVER_MAC_ADDRESS_OPCODE
                    *  value[1] - value[6] = macAddress
                    */
                    if (length == GATT_XPAN_SERVER_MAC_ADDRESS_OPCODE_SIZE)
                    {
                        GattXpanMacAddressInd *message = (GattXpanMacAddressInd *)CsrPmemZalloc(sizeof(GattXpanMacAddressInd));

                        message->cid = accessInd->btConnId;

                        xpanServerCpyArrayFromIterator(message->macAddress, &iter, GATT_XPAN_SERVER_MAC_ADDRESS_SIZE);

                        if (GATT_BUFF_ITERATOR_ERROR_DETECTED(&iter) != TRUE)
                        {
                            XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_MAC_ADDRESS_IND, message);
                        }
                        else
                        {
                            GATT_XPAN_SERVER_ERROR("Error - MAC address operation: unlikely error\n");
                            result = CSR_BT_GATT_ACCESS_RES_UNLIKELY_ERROR;
                            pfree(message);
                        }
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - MAC address operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }
                    break;
                }
                case GATT_XPAN_SERVER_BEARER_PREFERENCE_RESPONSE_OPCODE:
                {
                    /* The format for Bearer Preference Response is:
                    *  value[0] = 0x0C GATT_XPAN_SERVER_BEARER_PREFERENCE_RESPONSE_OPCODE
                    *  value[1] = status
                    */
                    if (length == GATT_XPAN_SERVER_BEARER_PREFERENCE_OPCODE_SIZE)
                    {
                        GattXpanBearerPreferenceResponseInd *message = (GattXpanBearerPreferenceResponseInd *)CsrPmemZalloc(sizeof(GattXpanBearerPreferenceResponseInd));

                        message->cid = accessInd->btConnId;
                        message->status = GattAccessIndIteratorRead8(&iter);
                        if (message->status > XPAN_SERVER_BEARER_PREFERENCE_STATUS_REJECTED)
                        {
                            GATT_XPAN_SERVER_ERROR("Error - Bearer Preference Response operation: invalid parameters\n");
                            result = GATT_XPAN_INVALID_DATA;
                            pfree(message);
                        }
                        else if (GATT_BUFF_ITERATOR_ERROR_DETECTED(&iter) != TRUE)
                        {
                            XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_BEARER_PREFERENCE_RESPONSE_IND, message);
                        }
                        else
                        {
                            pfree(message);
                            GATT_XPAN_SERVER_ERROR("Error - Bearer preference operation: unlikely error\n");
                            result = CSR_BT_GATT_ACCESS_RES_UNLIKELY_ERROR;
                        }
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - Bearer Preference operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }

                    break;
                }
                case GATT_XPAN_SERVER_UPDATE_BEACON_PARAMETERS_OPCODE:
                {
                    /* The format for Update Beacon Parameters is:
                    *  value[0] = 0x0D GATT_XPAN_SERVER_UPDATE_BEACON_PARAMETERS_OPCODE
                    *  value[1] - value[8] = nextTbttTsf
                    *  value[9] - value[10] = beaconInterval
                    */
                    if (length == GATT_XPAN_SERVER_UPDATE_BEACON_PARAMETERS_OPCODE_SIZE)
                    {
                        GattXpanUpdateBeaconParametersInd *message = (GattXpanUpdateBeaconParametersInd *)CsrPmemZalloc(sizeof(GattXpanUpdateBeaconParametersInd));

                        message->cid = accessInd->btConnId;

                        xpanServerCpyArrayFromIterator(message->nextTbttTsf, &iter, XPAN_NEXT_TBTT_TSF_SIZE);
                        message->beaconIntervalMultiplier = GattAccessIndIteratorRead16(&iter);
                        message->primaryFrequency = GattAccessIndIteratorRead16(&iter);

                        if (GATT_BUFF_ITERATOR_ERROR_DETECTED(&iter) != TRUE)
                        {
                            XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_UPDATE_BEACON_PARAMETERS_IND, message);
                        }
                        else
                        {
                            pfree(message);
                            GATT_XPAN_SERVER_ERROR("Error - Bearer preference operation: unlikely error\n");
                            result = CSR_BT_GATT_ACCESS_RES_UNLIKELY_ERROR;
                        }
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - Update beacon Parameters operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }
                    break;
                }
                case GATT_XPAN_SERVER_SAP_POWER_STATE_RESPONSE_OPCODE:
                {
                    /* The format for  is:
                    *  value[0] = 0x0E GATT_XPAN_SERVER_SAP_POWER_STATE_RESPONSE_OPCODE
                    *  value[1] = status
                    */
                    if (length == GATT_XPAN_SERVER_SAP_POWER_STATE_RESPONSE_OPCODE_SIZE)
                    {
                        GattXpanSapPowerStateResponseInd *message = (GattXpanSapPowerStateResponseInd *)CsrPmemZalloc(sizeof(GattXpanSapPowerStateResponseInd));

                        message->cid = accessInd->btConnId;
                        message->status = GattAccessIndIteratorRead8(&iter);
                        if (message->status <= XPAN_SERVER_SAP_POWER_STATE_STATUS_REJECTED)
                        {
                            if (GATT_BUFF_ITERATOR_ERROR_DETECTED(&iter) != TRUE)
                            {
                                XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_SAP_POWER_STATE_RESPONSE_IND, message);
                            }
                            else
                            {
                                pfree(message);
                                GATT_XPAN_SERVER_ERROR("Error - SAP power state response operation: unlikely error\n");
                                result = CSR_BT_GATT_ACCESS_RES_UNLIKELY_ERROR;
                            }
                        }
                        else
                        {
                            GATT_XPAN_SERVER_ERROR("Error - SAP power state response operation: invalid parameter\n");
                            result = GATT_XPAN_INVALID_DATA;
                            pfree(message);
                        }
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - SAP power state response operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }
                    break;
                }
                case GATT_XPAN_SERVER_CLIENT_FEATURES_OPCODE:
                {
                    /* The format for Client Features is:
                    *  value[0] = 0x0F GATT_XPAN_SERVER_CLIENT_FEATURES
                    *  value[1] - value[8] = features
                    */
                    if (length == XPAN_SERVER_CLIENT_FEATURES_OPCODE_SIZE)
                    {
                        uint8 *valuePtr = &accessInd->writeUnit[0].value[1];
                        if (XPAN_SERVER_CHECK_FEATURES_BITS_VALID(valuePtr))
                        {
                            GattXpanClientFeaturesInd *message = (GattXpanClientFeaturesInd *)CsrPmemZalloc(sizeof(GattXpanClientFeaturesInd));

                            message->cid = accessInd->btConnId;
                            xpanServerCpyArrayFromIterator(message->features, &iter, XPAN_SERVER_SERVER_FEATURES_SIZE);

                            if (GATT_BUFF_ITERATOR_ERROR_DETECTED(&iter) != TRUE)
                            {
                                XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_CLIENT_FEATURES_IND, message);
                            }
                            else
                            {
                                GATT_XPAN_SERVER_ERROR("Error - Client features operation: unlikely error\n");
                                result = CSR_BT_GATT_ACCESS_RES_UNLIKELY_ERROR;
                                pfree(message);
                            }
                        }
                        else
                        {
                            GATT_XPAN_SERVER_ERROR("Error - Client features operation: invalid parameter\n");
                            result = GATT_XPAN_INVALID_DATA;
                        }
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - Client features operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }

                    break;
                }
                case GATT_XPAN_SERVER_AUDIO_BEARER_SWITCH_REQUEST_OPCODE:
                {
                    /* The format for Audio Bearer Switch Request is:
                    *  value[0] = 0x10 GATT_XPAN_SERVER_AUDIO_BEARER_SWITCH_REQUEST
                    *  value[1] = newAudioBearer
                    */
                    if (length == XPAN_SERVER_AUDIO_BEARER_SWITCH_REQUEST_OPCODE_SIZE)
                    {
                        GattXpanAudioBearerSwitchRequestInd *message = (GattXpanAudioBearerSwitchRequestInd *)CsrPmemZalloc(sizeof(GattXpanAudioBearerSwitchRequestInd));

                        message->cid = accessInd->btConnId;
                        message->audioBearer = GattAccessIndIteratorRead8(&iter);
                        if (XPAN_SERVER_CHECK_BITS_VALID(message->audioBearer, XPAN_SERVER_AUDIO_BEARER_SWITCH_RESPONSE_VALID_BITS))
                        {

                            if (GATT_BUFF_ITERATOR_ERROR_DETECTED(&iter) != TRUE)
                            {
                                XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_AUDIO_BEARER_SWITCH_REQUEST_IND, message);
                            }
                            else
                            {
                                GATT_XPAN_SERVER_ERROR("Error - Audio bearer switch request operation: unlikely error\n");
                                result = CSR_BT_GATT_ACCESS_RES_UNLIKELY_ERROR;
                                pfree(message);
                            }
                        }
                        else
                        {
                            GATT_XPAN_SERVER_ERROR("Error - Audio bearer switch request operation: invalid parameter\n");
                            result = GATT_XPAN_INVALID_DATA;
                            pfree(message);
                        }
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - Audio bearer switch request operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }
                    break;
                }
                case GATT_XPAN_SERVER_WIFI_SCAN_RESULTS_OPCODE:
                {
                    GattXpanWiFiScanResultsInd* message = NULL;
                    uint8 message_scanTimestamp[XPAN_WIFI_SCAN_TIMESTAMP_LENGTH];
                    uint8 message_numBssids;

                    xpanServerCpyArrayFromIterator(message_scanTimestamp, &iter, XPAN_WIFI_SCAN_TIMESTAMP_LENGTH);
                    message_numBssids = GattAccessIndIteratorRead8(&iter);

                    if (message_numBssids > GATT_XPAN_SERVER_WIFI_SCAN_RESULT_NUM_APS_MAX)
                    {
                        GATT_BUFF_ITERATOR_SET_ERROR(&iter);
                        GATT_XPAN_SERVER_WARNING("Warning - WiFi Scan Result Opcode: unlikely error - num BSSIDs too large\n");
                        result = GATT_XPAN_INVALID_DATA;
                        break; /* exit the 'case' section */
                    }
                    /*
                     * Now that we know how big the message needs to be, we can allocate memory for it.
                     */
                    message = (GattXpanWiFiScanResultsInd*)CsrPmemZalloc(sizeof(GattXpanWiFiScanResultsInd) +
                                                                         (message_numBssids * sizeof (ApScanResult*)));
                    message->id =  GATT_XPAN_SERVER_WIFI_SCAN_RESULTS_IND;
                    message->cid = accessInd->btConnId;

                    memscpy(message->scanTimestamp, XPAN_WIFI_SCAN_TIMESTAMP_LENGTH, message_scanTimestamp, XPAN_WIFI_SCAN_TIMESTAMP_LENGTH);
                    /*
                     * For now we only support sending the complete set of ApScanResults in a single GattXpanWiFiScanResultsInd
                     */
                    message->moreData = FALSE;
                    message->numBssids = message_numBssids;

                    for (i = 0;
                        (i < message->numBssids) && ! GATT_BUFF_ITERATOR_ERROR_DETECTED(&iter);
                         i++)
                    {
                        message->apScanResult[i] = (ApScanResult*) CsrPmemZalloc(sizeof(ApScanResult));
                        message->apScanResult[i]->ssidLength = GattAccessIndIteratorRead8(&iter);
                        /* The 'ssidLength' shall not be invalid */
                        if (!XPAN_CHECK_SSID_LENGTH(message->apScanResult[i]->ssidLength))
                        {
                            GATT_BUFF_ITERATOR_SET_ERROR(&iter);
                            GATT_XPAN_SERVER_WARNING("Warning - WiFi Scan Result Opcode: unlikely error - Invalid SSID length\n");
                            break; /* exit the for loop (but not the 'case' section)*/
                        }
                        message->apScanResult[i]->ssid = GattAccessIndIteratorReadMultipleOctets(&iter, message->apScanResult[i]->ssidLength);

                        xpanServerCpyArrayFromIterator(message->apScanResult[i]->bssid, &iter, GATT_XPAN_SERVER_BSSID_SIZE);

                        message->apScanResult[i]->channelMHz = GattAccessIndIteratorRead16(&iter);
                        message->apScanResult[i]->securityMode = GattAccessIndIteratorRead8(&iter);
                        if (message->apScanResult[i]->securityMode >= XPAN_SECURITY_MODE_MIN_RESERVED_VALUE)
                        {
                            /* The 'reserved' security mode values should not be used */
                            GATT_BUFF_ITERATOR_SET_ERROR(&iter);
                            result = GATT_XPAN_INVALID_DATA;
                            GATT_XPAN_SERVER_WARNING("Warning - WiFi Scan Result Opcode: unlikely error - Security Mode out of range\n");
                            break; /* exit the for loop (but not the 'case' section)*/
                        }
                        message->apScanResult[i]->rssi = GattAccessIndIteratorRead8(&iter);
                    }
                    if(iter.bufferIndex != accessInd->writeUnitCount || iter.offset != 0 || GATT_BUFF_ITERATOR_ERROR_DETECTED(&iter))
                    {
                        GATT_XPAN_SERVER_WARNING("Error - WiFi Scan Result Opcode: Invalid Length\n");
                        result = result == CSR_BT_GATT_ACCESS_RES_SUCCESS ? GATT_XPAN_INVALID_LENGTH : result;
                        GattXpanServerFreeControlPointMessageContents(message);
                        pfree(message);
                        message = NULL;
                    }
                    else
                    {
                        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_WIFI_SCAN_RESULTS_IND, message);
                    }
                    break;
                }
                case GATT_XPAN_SERVER_CHANNEL_SWITCH_ANNOUNCEMENT_OPCODE:
                {
                    GattXpanChannelSwitchAnnouncementInd* message = (GattXpanChannelSwitchAnnouncementInd*)CsrPmemZalloc(sizeof(GattXpanChannelSwitchAnnouncementInd));

                    message->id =  GATT_XPAN_SERVER_CHANNEL_SWITCH_ANNOUNCEMENT_IND;
                    message->cid = accessInd->btConnId;
                    message->primaryFrequencyMHz = GattAccessIndIteratorRead16(&iter);
                    xpanServerCpyArrayFromIterator(message->targetTsf, &iter, XPAN_TARGET_TSF_LENGTH);
                    message->bandwidthMHz = GattAccessIndIteratorRead8(&iter);

                    if(iter.bufferIndex != accessInd->writeUnitCount || iter.offset != 0 || GATT_BUFF_ITERATOR_ERROR_DETECTED(&iter))
                    {
                        GATT_XPAN_SERVER_WARNING("Error - Channel Switch Annoucement Opcode: Invalid Length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                        GattXpanServerFreeControlPointMessageContents(message);
                        pfree(message);
                        message = NULL;
                    }
                    else
                    {
                        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_CHANNEL_SWITCH_ANNOUNCEMENT_IND, message);
                    }

                    break;
                }
                case GATT_XPAN_SERVER_UDP_SYNC_PORT_OPCODE:
                {
                    GattXpanUdpSyncPortInd* message = (GattXpanUdpSyncPortInd*)CsrPmemZalloc(sizeof(GattXpanUdpSyncPortInd));
                    message->id =  GATT_XPAN_SERVER_UDP_SYNC_PORT_IND;
                    message->cid = accessInd->btConnId;
                    message->udpSyncPort = GattAccessIndIteratorRead16(&iter);

                    if (length == GATT_XPAN_SERVER_UDP_SYNC_PORT_OPCODE_SIZE)
                    {
                        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_UDP_SYNC_PORT_IND, message);
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - UDP Sync Port operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }
                    break;
                }
                case GATT_XPAN_SERVER_ROAMING_REQUEST_OPCODE:
                {
                    GattXpanRoamingRequestInd* message = (GattXpanRoamingRequestInd*)CsrPmemZalloc(sizeof(GattXpanRoamingRequestInd));
                    message->id =  GATT_XPAN_SERVER_ROAMING_REQUEST_IND;
                    message->cid = accessInd->btConnId;

                    if (length == GATT_XPAN_SERVER_ROAMING_REQUEST_OPCODE_SIZE)
                    {
                        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_ROAMING_REQUEST_IND, message);
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - Roaming Request operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }
                    break;
                }
                case GATT_XPAN_SERVER_MULTICAST_MAC_ADDRESS_OPCODE:
                {
                    GattXpanMulticastMacAddressInd* message = (GattXpanMulticastMacAddressInd*)CsrPmemZalloc(sizeof(GattXpanMulticastMacAddressInd));
                    message->id =  GATT_XPAN_SERVER_MULTICAST_MAC_ADDRESS_IND;
                    message->cid = accessInd->btConnId;
                    xpanServerCpyArrayFromIterator(message->multicastMacAddress, &iter, GATT_XPAN_SERVER_MAC_ADDRESS_SIZE);

                    if (length == GATT_XPAN_SERVER_MULTICAST_MAC_ADDRESS_OPCODE_SIZE)
                    {
                        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_MULTICAST_MAC_ADDRESS_IND, message);
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - Multicast MAC Address operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }
                    break;
                }
                case GATT_XPAN_SERVER_USECASE_IDENTIFIER_OPCODE:
                {
                    GattXpanUseCaseIdentifierInd* message = (GattXpanUseCaseIdentifierInd*)CsrPmemZalloc(sizeof(GattXpanUseCaseIdentifierInd));
                    message->id =  GATT_XPAN_SERVER_USECASE_IDENTIFIER_IND;
                    message->cid = accessInd->btConnId;
                    message->useCaseIdentifier = GattAccessIndIteratorRead8(&iter);
                    message->periodicity = GattAccessIndIteratorRead16(&iter);

                    if (length == GATT_XPAN_SERVER_USE_CASE_IDENTIFER_OPCODE_SIZE)
                    {
                        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_USECASE_IDENTIFIER_IND, message);
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - Use Case Identifier operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }
                    break;
                }
                case GATT_XPAN_SERVER_AP_CONNECT_ASSIST_OPCODE:
                {
                    GattXpanApConnectAssistInd* message = (GattXpanApConnectAssistInd*)CsrPmemZalloc(sizeof(GattXpanApConnectAssistInd));
                    message->id =  GATT_XPAN_SERVER_AP_CONNECT_ASSIST_IND;
                    message->cid = accessInd->btConnId;
                    message->ssidLength = GattAccessIndIteratorRead8(&iter);
                    message->ssid = GattAccessIndIteratorReadMultipleOctets(&iter, message->ssidLength);
                    xpanServerCpyArrayFromIterator(message->bssId, &iter, GATT_XPAN_SERVER_BSSID_SIZE);
                    xpanServerCpyArrayFromIterator(message->ptk, &iter, GATT_XPAN_SERVER_WIFI_TEMPORAL_KEY_SIZE);
                    xpanServerCpyArrayFromIterator(message->gtk, &iter, GATT_XPAN_SERVER_WIFI_TEMPORAL_KEY_SIZE);
                    xpanServerCpyArrayFromIterator(message->dhcpServerIpAddress, &iter, GATT_XPAN_SERVER_IPV4_ADDRESS_SIZE);
                    xpanServerCpyArrayFromIterator(message->dnsServerIpAddress, &iter, GATT_XPAN_SERVER_IPV4_ADDRESS_SIZE);
                    xpanServerCpyArrayFromIterator(message->subnetMask, &iter, GATT_XPAN_SERVER_IPV4_ADDRESS_SIZE);
                    xpanServerCpyArrayFromIterator(message->broadcastAddress, &iter, GATT_XPAN_SERVER_IPV4_ADDRESS_SIZE);
                    xpanServerCpyArrayFromIterator(message->routerAddress, &iter, GATT_XPAN_SERVER_IPV4_ADDRESS_SIZE);
                    xpanServerCpyArrayFromIterator(message->ipAddressLeaseTime, &iter, GATT_XPAN_SERVER_IP_ADDRESS_TIME_SIZE);
                    xpanServerCpyArrayFromIterator(message->renewalTimeValue, &iter, GATT_XPAN_SERVER_IP_ADDRESS_TIME_SIZE);
                    xpanServerCpyArrayFromIterator(message->rebindingTimeValue, &iter, GATT_XPAN_SERVER_IP_ADDRESS_TIME_SIZE);
                    message->numIpAddresses = GattAccessIndIteratorRead8(&iter);
                    message->ipv4Address = (uint8*) CsrPmemZalloc(sizeof(uint8) * GATT_XPAN_SERVER_IPV4_ADDRESS_SIZE * message->numIpAddresses);
                    message->macAddress = (uint8*) CsrPmemZalloc(sizeof(uint8) * GATT_XPAN_SERVER_MAC_ADDRESS_SIZE * message->numIpAddresses);

                    for (i = 0; (i < message->numIpAddresses) && ! GATT_BUFF_ITERATOR_ERROR_DETECTED(&iter);i++)
                    {
                        xpanServerCpyArrayFromIterator(&message->ipv4Address[i * GATT_XPAN_SERVER_IPV4_ADDRESS_SIZE], &iter, GATT_XPAN_SERVER_IPV4_ADDRESS_SIZE);
                        xpanServerCpyArrayFromIterator(&message->ipv4Address[i * GATT_XPAN_SERVER_MAC_ADDRESS_SIZE], &iter, GATT_XPAN_SERVER_MAC_ADDRESS_SIZE);
                    }

                    if(iter.bufferIndex != accessInd->writeUnitCount || iter.offset != 0 || GATT_BUFF_ITERATOR_ERROR_DETECTED(&iter))
                    {
                        GATT_XPAN_SERVER_WARNING("Error - AP connect Assist Opcode: Invalid Length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                        GattXpanServerFreeControlPointMessageContents(message);
                        pfree(message);
                        message = NULL;
                    }
                    else
                    {
                        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_AP_CONNECT_ASSIST_IND, message);
                    }
                    break;
                }
                case GATT_XPAN_SERVER_WIFI_CHANNEL_SWITCH_RESPONSE_OPCODE:
                {
                    GattXpanWiFiChannelSwitchResponseInd* message = (GattXpanWiFiChannelSwitchResponseInd*)CsrPmemZalloc(sizeof(GattXpanWiFiChannelSwitchResponseInd));
                    message->id =  GATT_XPAN_SERVER_WIFI_CHANNEL_SWITCH_RESPONSE_IND;
                    message->cid = accessInd->btConnId;
                    message->status = GattAccessIndIteratorRead8(&iter);

                    if (length == GATT_XPAN_SERVER_WIFI_CHANNEL_SWITCH_RESPONSE_OPCODE_SIZE)
                    {
                        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_WIFI_CHANNEL_SWITCH_RESPONSE_IND, message);
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - WiFi Channel Switch Response operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                    }
                    break;
                }
                case GATT_XPAN_SERVER_BEARER_SWITCH_FAILED_OPCODE:
                {
                    /* The format for Update Bearer Switch Failed opcode is:
                    *  value[0] = 0x19 GATT_XPAN_SERVER_BEARER_SWITCH_FAILED_OPCODE
                    *  value[1] = reason
                    *  value[2] = role
                    */
                    GattXpanBearerSwitchFailedInd* message = (GattXpanBearerSwitchFailedInd*)CsrPmemZalloc(sizeof(GattXpanBearerSwitchFailedInd));
                    message->id =  GATT_XPAN_SERVER_BEARER_SWITCH_FAILED_IND;
                    message->cid = accessInd->btConnId;
                    message->reason = GattAccessIndIteratorRead8(&iter);
                    message->role = GattAccessIndIteratorRead8(&iter);

                    if (length == GATT_XPAN_SERVER_BEARER_SWITCH_FAILED_OPCODE_SIZE)
                    {
                        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_BEARER_SWITCH_FAILED_IND, message);
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - Bearer Switch Failed opcode: Invalid Length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                        pfree(message);
                        message = NULL;
                    }
                    break;
                }
                case GATT_XPAN_SERVER_COUNTRY_STRING_OPCODE:
                {
                    /* The format for Update Country String opcode is:
                    *  value[0] = 0x1A GATT_XPAN_SERVER_COUNTRY_STRING_OPCODE
                    *  value[1] - value[3] = countryString
                    */
                    GattXpanCountryStringInd* message = (GattXpanCountryStringInd*)CsrPmemZalloc(sizeof(GattXpanCountryStringInd));
                    message->id =  GATT_XPAN_SERVER_COUNTRY_STRING_IND;
                    message->cid = accessInd->btConnId;
                    xpanServerCpyArrayFromIterator(message->countryString, &iter, GATT_XPAN_SERVER_COUNTRY_STRING_SIZE);

                    if (length == GATT_XPAN_SERVER_COUNTRY_STRING_OPCODE_SIZE)
                    {
                        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_COUNTRY_STRING_IND, message);
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - Country String opcode: Invalid Length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                        pfree(message);
                        message = NULL;
                    }
                    break;
                }
                case GATT_XPAN_SERVER_SAP_STATE_OPCODE:
                {
                    GattXpanSapStateInd* message = (GattXpanSapStateInd*)CsrPmemZalloc(sizeof(GattXpanSapStateInd));
                    message->id =  GATT_XPAN_SERVER_SAP_STATE_IND;
                    message->cid = accessInd->btConnId;
                    message->state = GattAccessIndIteratorRead8(&iter);
                    message->reason = GattAccessIndIteratorRead8(&iter);

                    if (length == GATT_XPAN_SERVER_SAP_STATE_OPCODE_SIZE)
                    {
                        XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_SAP_STATE_IND, message);
                    }
                    else
                    {
                        GATT_XPAN_SERVER_ERROR("Error - Sap State operation: invalid length\n");
                        result = GATT_XPAN_INVALID_LENGTH;
                        pfree(message);
                        message = NULL;
                    }
                    break;
                }
                case GATT_XPAN_SERVER_CONNECTED_ENTERPRISE_SSID_OPCODE:
                {
                    /* Handle the write and alter result depending on the validation results*/
                    result = xpanServerConnectedEnterpriseSsidHandle(gattXpanServerInstance, &iter);
                    break;
                }
                default:
                {
                    GATT_XPAN_SERVER_ERROR("Error - Invalid opcode recieved\n");
                    result = GATT_XPAN_SERVER_ERR_UNSUPPORTED_OPCODE;
                    break;
                }
            }
        }

        xpanServerSendAccessRsp(gattXpanServerInstance->gattId,
                                accessInd->btConnId,
                                accessInd->attrHandle,
                                result,
                                0,
                                NULL);

    }
}

/****************************************************************
 * NAME
 *      xpanServerHandleAudioBearerSwitchResponseRead
 *
 * DESCRIPTION
 *      Deals with read access of the HANDLE_AUDIO_BEARER_SWITCH_RESPONSE handle.
 * **************************************************************/
void xpanServerHandleAudioBearerSwitchResponseRead(
        GattXpanServerData *gattXpanServerInstance,
        CsrBtGattDbAccessReadInd *const accessInd)
{
    GattBuffIterator iter;
    XpanClientDataElement *client = xpanFindClient(&(gattXpanServerInstance->data.connectedClients), accessInd->btConnId);
    uint16 valueLength = XPAN_SERVER_AUDIO_BEARER_SWITCH_RESPONSE_SIZE;
    uint8 *value = (uint8 *)CsrPmemAlloc(sizeof(uint8)*valueLength);
    if (client)
    {
        GattBuffIteratorInitialise(&iter, value, valueLength);
        GattBuffIteratorWrite8(&iter, client->clientData.audioBearerStatus);

        xpanServerRespondToCharacteristicRead(accessInd, value, valueLength, gattXpanServerInstance->gattId);
    }
    else
    {
        GATT_XPAN_SERVER_ERROR("HANDLE_AUDIO_BEARER_SWITCH_RESPONSE: CSR_BT_GATT_RESULT_INTERNAL_ERROR\n");
        xpanServerSendAccessErrorRsp(
                gattXpanServerInstance->gattId,
                accessInd->btConnId,
                accessInd->attrHandle,
                CSR_BT_GATT_RESULT_INTERNAL_ERROR);
    }
}

/***************************************************************************/
void xpanServerHandleAccessReadIndication(
        GattXpanServerData *gattXpanServerInstance,
        CsrBtGattDbAccessReadInd *const accessInd)
{
    uint16 valueLength = 0;
    uint8 *value = NULL;

    switch(accessInd->attrHandle)
    {
        case HANDLE_STORED_SSID:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_STORED_SSID\n");
            value = xpanServerComposeStoredSsidValue(&valueLength, gattXpanServerInstance);
            xpanServerRespondToCharacteristicRead(accessInd, value, valueLength, gattXpanServerInstance->gattId);
            break;
        }
        case HANDLE_IPV4_ADDRESSES:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_IPV4_ADDRESSES\n");
            value = xpanServerComposeIpv4AddressValue(&valueLength, gattXpanServerInstance);
            xpanServerRespondToCharacteristicRead(accessInd, value, valueLength, gattXpanServerInstance->gattId);
            break;
        }
        case HANDLE_IPV6_ADDRESSES:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_IPV6_ADDRESSES\n");
            value = xpanServerComposeIpv6AddressValue(&valueLength, gattXpanServerInstance);
            xpanServerRespondToCharacteristicRead(accessInd, value, valueLength, gattXpanServerInstance->gattId);
            break;
        }
        case HANDLE_L2CAP_TCP_PORT:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_L2CAP_TCP_PORT\n");
            xpanCharacteristicReadResponse16(accessInd, gattXpanServerInstance->data.l2capTcpPort, gattXpanServerInstance->gattId);
            break;
        }
        case HANDLE_UDP_PORT:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_UDP_PORT\n");
            xpanCharacteristicReadResponse16(accessInd, gattXpanServerInstance->data.udpPort, gattXpanServerInstance->gattId);
            break;
        }
        case HANDLE_MDNS_SRV_UUID:
        {
            GattBuffIterator iter;
            GATT_XPAN_SERVER_INFO("HANDLE_MDNS_SRV_UUID\n");
            valueLength = sizeof(uint8)*GATT_XPAN_SERVER_MDNS_SRV_UUID_SIZE;
            value = (uint8 *)CsrPmemAlloc(valueLength);
            GattBuffIteratorInitialise(&iter, value, valueLength);
            GattBuffIteratorWriteMultipleOctets(&iter, gattXpanServerInstance->data.mDnsSrvUuid, GATT_XPAN_SERVER_MDNS_SRV_UUID_SIZE);
            xpanServerSendAccessRsp(gattXpanServerInstance->gattId, accessInd->btConnId, accessInd->attrHandle, CSR_BT_GATT_RESULT_SUCCESS, valueLength, value);
            break;
        }
        case HANDLE_TWT_CONFIGURATION:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_TWT_CONFIGURATION\n");
            value = xpanServerComposeTwtConfigurationValue(&valueLength, gattXpanServerInstance, accessInd->btConnId);
            xpanServerRespondToCharacteristicRead(accessInd, value, valueLength, gattXpanServerInstance->gattId);
            break;
        }
        case HANDLE_CONNECTED_DEVICES:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_CONNECTED_DEVICES\n");
            if(gattXpanServerInstance->data.connectedDevices.numDevices == 0)
            {
                xpanServerSendAccessRsp(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    CSR_BT_GATT_RESULT_SUCCESS,
                    0,
                    value);
            }
            else
            {
                value = xpanServerComposeConnectedDevicesValue(&valueLength, gattXpanServerInstance);
                xpanServerRespondToCharacteristicRead(accessInd, value, valueLength, gattXpanServerInstance->gattId);
            }
            break;
        }
        case HANDLE_CLEAR_TO_SEND:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_CLEAR_TO_SEND\n");
            xpanServerHandleClearToSendRead(gattXpanServerInstance, accessInd);
            break;
        }
        case HANDLE_BEARER_PREFERENCE:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_BEARER_PREFERENCE\n");
            if((gattXpanServerInstance->characteristicsBitMask[0]) & GATT_XPAN_CHARACTERISTICS_MASK_BEARER_PREFERENCE)
            {
                GattXpanBearerPreferenceReadInd *message = (GattXpanBearerPreferenceReadInd *)CsrPmemZalloc(sizeof(GattXpanBearerPreferenceReadInd));
                message->cid = accessInd->btConnId;
                XpanMessageSend(gattXpanServerInstance->appTask, GATT_XPAN_SERVER_BEARER_PREFERENCE_READ_IND, message);
            }
            else
            {
                value = xpanServerComposeBearerPreferenceValue(&valueLength, gattXpanServerInstance);
                xpanServerRespondToCharacteristicRead(accessInd, value, valueLength, gattXpanServerInstance->gattId);
            }
            break;
        }
        case HANDLE_MAC_ADDRESSES:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_MAC_ADDRESSES\n");
            value = xpanServerComposeMacAddressValue(&valueLength, gattXpanServerInstance);
            xpanServerRespondToCharacteristicRead(accessInd, value, valueLength, gattXpanServerInstance->gattId);
            break;
        }
        case HANDLE_REQUESTED_SAP_POWER_STATE:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_REQUESTED_SAP_POWER_STATE\n");
            xpanCharacteristicReadResponse8(accessInd, gattXpanServerInstance->data.requestedSapPowerState, gattXpanServerInstance->gattId);
            break;
        }
        case HANDLE_SERVER_FEATURES:
        {
            GattBuffIterator iter;
            GATT_XPAN_SERVER_INFO("HANDLE_SERVER_FEATURES\n");
            valueLength = XPAN_SERVER_SERVER_FEATURES_SIZE;
            value = (uint8 *)CsrPmemAlloc(sizeof(uint8)*valueLength);
            GattBuffIteratorInitialise(&iter, value, valueLength);
            GattBuffIteratorWriteMultipleOctets(&iter, gattXpanServerInstance->data.features, XPAN_SERVER_SERVER_FEATURES_SIZE);
            xpanServerSendAccessRsp(gattXpanServerInstance->gattId, accessInd->btConnId, accessInd->attrHandle, CSR_BT_GATT_RESULT_SUCCESS, valueLength, value);
            break;
        }
        case HANDLE_AUDIO_BEARER_SWITCH_RESPONSE:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_AUDIO_BEARER_SWITCH_RESPONSE\n");
            xpanServerHandleAudioBearerSwitchResponseRead(gattXpanServerInstance, accessInd);
            break;
        }
        case HANDLE_NUM_DEVICES_PRESENT:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_NUM_DEVICES_PRESENT\n");
            xpanCharacteristicReadResponse8(accessInd, gattXpanServerInstance->data.numDevices, gattXpanServerInstance->gattId);
            break;
        }
        case HANDLE_VOICE_BACK_CHANNEL_PERIODICITY:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_VOICE_BACK_CHANNEL_PERIODICITY\n");
            xpanCharacteristicReadResponse8(accessInd, gattXpanServerInstance->data.periodicity, gattXpanServerInstance->gattId);
            break;
        }
        case HANDLE_TWT_STATUS:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_TWT_STATUS\n");
            xpanCharacteristicReadResponse32(accessInd, gattXpanServerInstance->data.twtStatus, gattXpanServerInstance->gattId);
            break;
        }
        case HANDLE_SAP_CONNECTION_STATUS:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_SAP_CONNECTION_STATUS\n");
            xpanCharacteristicReadResponse32(accessInd, gattXpanServerInstance->data.sapConnectionStatus, gattXpanServerInstance->gattId);
            break;
        }
        case HANDLE_STORED_SSID_CLIENT_CONFIG:
        /* Fallthrough */
        case HANDLE_IPV4_ADDRESSES_CLIENT_CONFIG:
        case HANDLE_IPV6_ADDRESSES_CLIENT_CONFIG:
        case HANDLE_L2CAP_TCP_PORT_CLIENT_CONFIG:
        case HANDLE_UDP_PORT_CLIENT_CONFIG:
        case HANDLE_CONNECTED_DEVICES_CLIENT_CONFIG:
        case HANDLE_CLEAR_TO_SEND_CLIENT_CONFIG:
        case HANDLE_BEARER_PREFERENCE_CLIENT_CONFIG:
        case HANDLE_REQUESTED_SAP_POWER_STATE_CLIENT_CONFIG:
        case HANDLE_SERVER_FEATURES_CLIENT_CONFIG:
        case HANDLE_AUDIO_BEARER_SWITCH_RESPONSE_CLIENT_CONFIG:
        case HANDLE_NUM_DEVICES_PRESENT_CLIENT_CONFIG:
        case HANDLE_VOICE_BACK_CHANNEL_PERIODICITY_CLIENT_CONFIG:
        case HANDLE_REQUEST_WIFI_SCAN_RESULTS_CLIENT_CONFIG:
        case HANDLE_ROAMING_REQUEST_RESPONSE_CLIENT_CONFIG:
        case HANDLE_MAC_ADDRESSES_CLIENT_CONFIG:
        case HANDLE_WIFI_SCAN_RESULTS_CLIENT_CONFIG:
        case HANDLE_PREFERRED_CHANNELS_CLIENT_CONFIG:
        case HANDLE_WIFI_CHANNEL_SWITCH_REQUEST_CLIENT_CONFIG:
        case HANDLE_SUPPORTED_WIFI_CHANNELS_CLIENT_CONFIG:
        case HANDLE_TWT_STATUS_CLIENT_CONFIG:
        case HANDLE_SAP_CONNECTION_STATUS_CLIENT_CONFIG:
        {
            xpanServerHandleReadIndCcc(gattXpanServerInstance, accessInd);
            break;
        }
        default:
        {
            GATT_XPAN_SERVER_INFO("ERROR: xpanServerHandleAccessReadIndication invalid handle received.");
            xpanServerSendAccessErrorRsp(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    CSR_BT_GATT_ACCESS_RES_INVALID_HANDLE);
        }
    }
}

/***************************************************************************/
void xpanServerHandleAccessWriteIndication(
        GattXpanServerData *gattXpanServerInstance,
        CsrBtGattDbAccessWriteInd *const accessInd)
{
    switch (accessInd->attrHandle)
    {
        case HANDLE_TWT_CONFIGURATION:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_TWT_CONFIGURATION write\n");
            xpanServerHandleTwtConfigurationAccess(gattXpanServerInstance, accessInd);
            break;
        }
        case HANDLE_XPAN_CONTROL_POINT:
        {
            GATT_XPAN_SERVER_INFO("HANDLE_XPAN_CONTROL_POINT write\n");
            xpanServerHandleXpanControlPointWrite(gattXpanServerInstance, accessInd);
            break;
        }
        case HANDLE_STORED_SSID_CLIENT_CONFIG:
        /* Fallthrough */
        case HANDLE_IPV4_ADDRESSES_CLIENT_CONFIG:
        case HANDLE_IPV6_ADDRESSES_CLIENT_CONFIG:
        case HANDLE_L2CAP_TCP_PORT_CLIENT_CONFIG:
        case HANDLE_UDP_PORT_CLIENT_CONFIG:
        case HANDLE_CONNECTED_DEVICES_CLIENT_CONFIG:
        case HANDLE_CLEAR_TO_SEND_CLIENT_CONFIG:
        case HANDLE_BEARER_PREFERENCE_CLIENT_CONFIG:
        case HANDLE_REQUESTED_SAP_POWER_STATE_CLIENT_CONFIG:
        case HANDLE_SERVER_FEATURES_CLIENT_CONFIG:
        case HANDLE_AUDIO_BEARER_SWITCH_RESPONSE_CLIENT_CONFIG:
        case HANDLE_NUM_DEVICES_PRESENT_CLIENT_CONFIG:
        case HANDLE_VOICE_BACK_CHANNEL_PERIODICITY_CLIENT_CONFIG:
        case HANDLE_REQUEST_WIFI_SCAN_RESULTS_CLIENT_CONFIG:
        case HANDLE_ROAMING_REQUEST_RESPONSE_CLIENT_CONFIG:
        case HANDLE_MAC_ADDRESSES_CLIENT_CONFIG:
        case HANDLE_WIFI_SCAN_RESULTS_CLIENT_CONFIG:
        case HANDLE_PREFERRED_CHANNELS_CLIENT_CONFIG:
        case HANDLE_WIFI_CHANNEL_SWITCH_REQUEST_CLIENT_CONFIG:
        case HANDLE_SUPPORTED_WIFI_CHANNELS_CLIENT_CONFIG:
        case HANDLE_TWT_STATUS_CLIENT_CONFIG:
        case HANDLE_SAP_CONNECTION_STATUS_CLIENT_CONFIG:
        {
            GATT_XPAN_SERVER_INFO("xpanServerHandleAccessWriteIndication: Handle (0x%04X) is being written to\n.", accessInd->attrHandle);
            xpanServerHandleWriteClientConfigAccess(gattXpanServerInstance, accessInd);
            break;
        }
        case HANDLE_STORED_SSID:
        /* Fallthrough */
        case HANDLE_IPV4_ADDRESSES:
        case HANDLE_IPV6_ADDRESSES:
        case HANDLE_L2CAP_TCP_PORT:
        case HANDLE_UDP_PORT:
        case HANDLE_MDNS_SRV_UUID:
        case HANDLE_CONNECTED_DEVICES:
        case HANDLE_CLEAR_TO_SEND:
        case HANDLE_BEARER_PREFERENCE:
        case HANDLE_MAC_ADDRESSES:
        case HANDLE_REQUESTED_SAP_POWER_STATE:
        case HANDLE_SERVER_FEATURES:
        case HANDLE_AUDIO_BEARER_SWITCH_RESPONSE:
        case HANDLE_NUM_DEVICES_PRESENT:
        case HANDLE_VOICE_BACK_CHANNEL_PERIODICITY:
        case HANDLE_ROAMING_REQUEST_RESPONSE:
        case HANDLE_WIFI_SCAN_RESULTS:
        case HANDLE_PREFERRED_CHANNELS:
        case HANDLE_WIFI_CHANNEL_SWITCH_REQUEST:
        case HANDLE_SUPPORTED_WIFI_CHANNELS:
        case HANDLE_TWT_STATUS:
        case HANDLE_SAP_CONNECTION_STATUS:
        {
            GATT_XPAN_SERVER_INFO("ERROR: xpanServerHandleAccessWriteIndication handle (0x%04X) is not writable.\n",
                                  accessInd->attrHandle);
            xpanServerSendAccessErrorRsp(
                gattXpanServerInstance->gattId,
                accessInd->btConnId,
                accessInd->attrHandle,
                CSR_BT_GATT_ACCESS_RES_WRITE_NOT_PERMITTED);
            break;
        }
        default:
        {
            GATT_XPAN_SERVER_INFO("ERROR: xpanServerHandleAccessWriteIndication invalid handle (0x%04X) received.\n",
                                  accessInd->attrHandle);
            xpanServerSendAccessErrorRsp(
                gattXpanServerInstance->gattId,
                accessInd->btConnId,
                accessInd->attrHandle,
                CSR_BT_GATT_ACCESS_RES_INVALID_HANDLE);
        }
    }
}


void xpanServerHandleReadIndCcc(GattXpanServerData *gattXpanServerInstance,
                                CsrBtGattDbAccessReadInd *const accessInd)
{
    XpanClientDataElement *client = xpanFindClient(&gattXpanServerInstance->data.connectedClients, accessInd->btConnId);

    if(client)
    {
        switch (accessInd->attrHandle)
        {
            case HANDLE_STORED_SSID_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_STORED_SSID_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.storedSsidClientCfg);
                break;
            }
            case HANDLE_IPV4_ADDRESSES_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_IPV4_ADDRESSES_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.ipv4AddressClientCfg);
                break;
            }
            case HANDLE_IPV6_ADDRESSES_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_IPV6_ADDRESSES_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.ipv6AddressClientCfg);
                break;
            }
            case HANDLE_L2CAP_TCP_PORT_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_L2CAP_TCP_PORT_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.l2capTcpPortClientCfg);
                break;
            }
            case HANDLE_UDP_PORT_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_UDP_PORT_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.udpPortClientCfg);
                break;
            }
            case HANDLE_CONNECTED_DEVICES_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_CONNECTED_DEVICES_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.connectedDevicesClientCfg);
                break;
            }
            case HANDLE_CLEAR_TO_SEND_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_CLEAR_TO_SEND_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.clearToSendCfg);
                break;
            }
            case HANDLE_BEARER_PREFERENCE_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_BEARER_PREFERENCE_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.bearerPreferenceClientCfg);
                break;
            }
            case HANDLE_REQUESTED_SAP_POWER_STATE_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_REQUESTED_SAP_POWER_STATE_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.requestedSapPowerStateCfg);
                break;
            }
            case HANDLE_SERVER_FEATURES_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_SERVER_FEATURES_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.serverFeaturesCfg);
                break;
            }
            case HANDLE_AUDIO_BEARER_SWITCH_RESPONSE_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_AUDIO_BEARER_SWITCH_RESPONSE_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.audioBearerSwitchResponseCfg);
                break;
            }
            case HANDLE_NUM_DEVICES_PRESENT_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_NUM_DEVICES_PRESENT_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.numDevicesPresentClientCfg);
                break;
            }
            case HANDLE_VOICE_BACK_CHANNEL_PERIODICITY_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_VOICE_BACK_CHANNEL_PERIODICITY_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.voiceBackChannelPeriodicityClientCfg);
                break;
            }
            case HANDLE_REQUEST_WIFI_SCAN_RESULTS_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_REQUEST_WIFI_SCAN_RESULTS_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.requestWiFiScanResultsClientCfg);
                break;
            }
            case HANDLE_ROAMING_REQUEST_RESPONSE_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_ROAMING_REQUEST_RESPONSE_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.roamingRequestResponseClientCfg);
                break;
            }

            case HANDLE_MAC_ADDRESSES_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_MAC_ADDRESSES_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.macAddressesClientCfg);
                break;
            }

            case HANDLE_WIFI_SCAN_RESULTS_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_WIFI_SCAN_RESULTS_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.wiFiScanResultsClientCfg);
                break;
            }

            case HANDLE_PREFERRED_CHANNELS_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_PREFERRED_CHANNELS_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.preferredChannelsClientCfg);
                break;
            }

            case HANDLE_WIFI_CHANNEL_SWITCH_REQUEST_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_WIFI_CHANNEL_SWITCH_REQUEST_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.wiFiChannelSwitchRequestClientCfg);
                break;
            }

            case HANDLE_SUPPORTED_WIFI_CHANNELS_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_SUPPORTED_WIFI_CHANNELS_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.supportedWiFiChannelsClientCfg);
                break;
            }

            case HANDLE_TWT_STATUS_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_TWT_STATUS_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.twtStatusClientCfg);
                break;
            }

            case HANDLE_SAP_CONNECTION_STATUS_CLIENT_CONFIG:
            {
                GATT_XPAN_SERVER_INFO("HANDLE_SAP_CONNECTION_STATUS_CLIENT_CONFIG read\n");
                xpanServerHandleReadClientConfigAccess(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    client->clientData.clientCfg.sapConnectionStatusClientCfg);
                break;
            }

            default:
            {
                GATT_XPAN_SERVER_INFO("ERROR: xpanServerHandleAccessWriteIndication invalid handle (0x%04X) received.\n",
                                      accessInd->attrHandle);
                xpanServerSendAccessErrorRsp(
                    gattXpanServerInstance->gattId,
                    accessInd->btConnId,
                    accessInd->attrHandle,
                    CSR_BT_GATT_ACCESS_RES_INVALID_HANDLE);
                break;
            }
        }
    }
    else
    {
        xpanServerSendAccessErrorRsp(
            gattXpanServerInstance->gattId,
            accessInd->btConnId,
            accessInd->attrHandle,
            CSR_BT_GATT_RESULT_INTERNAL_ERROR);
    }
}

#endif /* EXCLUDE_GATT_XPAN_SERVER_MODULE */
